12.基本ライブラリ

12-4. ファイル入出力

◇ファイル入出力

 ファイル入出力は今回が最初なので基本的な操作に留めて、
  ・ファイルの定義
  ・ファイルを開く
  ・上書き保存
  ・ファイルを閉じる
の3つの操作を行います。

1.ファイルの定義

 ファイルも1つあるいは連続したデータであるので、ファイルを格納する変数が必要になります。これをファイル型の構造体としてC言語で宣言します。

一般的に変数名として fp を使うことが多いのでそれを例に宣言します。
ちなみに fp の意味は File Pointer (ファイルポインタ)です。

FILE *fp;

この FILE 型は stdio.h 内に定義されています。

2.ファイルを開く

 ファイルを開くには fopen() を使います。

必要なヘッダ:stdio.h
関数のタイプ:FILE fopen(const char *filename, const char *mode);
引数    :filename ファイル名の文字列ポインタ
       mode オープンモードの文字列ポインタ
戻り値   :成功(ファイルデータのアドレス)・失敗(NULL)

 今回は、上書き保存を行うので、モードは w (上書き保存・テキスト形式)にします。ファイル名は readme.txt を例にします。

fp = fopen(“readme.txt”,”w”);

 fp に代入しているのは開いたファイルデータの先頭アドレスになります。
ファイルのオープンに失敗すれば fp はNULLになってしまいます。

3.上書き保存

 今度は、この readme.txt に対して文字列を上書き保存してみます。
このとき使う関数は fprintf() です。

必要なヘッダ:stdio.h
関数のタイプ:FILE fprintf(FILE *stream, const char *format, …);
引数    :stream FILE型変数へのポインタ
       format 書式付文字列のポインタ
戻り値   :成功(出力した文字数)・失敗(負の値)

 例として、readme.txt に「はじめにお読みください」と書き出すとすれば、

fprintf(fp,”はじめにお読みください\n”);

とすれば完了します。使い方はprintfと同じなので変数の値を書き出すこともできます。

4.ファイルを閉じる

 最後に開いたファイルはクローズしなければなりません。
これを怠ると処理系によってはファイルが使用中のままになりOSや他のアプリケーションに迷惑をかけることになりますので必ず行ってください。
 特にCGI等ではサーバーが深刻なリソース不足に陥ってしまうこともあります。

 ファイルをクローズするときに使用する関数は fclose() です。

必要なヘッダ:stdio.h
関数のタイプ:FILE fclose(FILE *stream);
引数    :stream FILE型変数へのポインタ
戻り値   :成功(0)・失敗(EOF)

fclose(fp);

ここまでで、今日の一連の流れをプログラムにしてみます。

#include<stdio.h>

main()
{
    FILE *fp;
    fp = fopen("readme.txt","w");
    fprintf(fp,"はじめにお読みください\n");
    fclose(fp);
}

◇fopen()の解説

 fopen()のモードには”w”以外にも。

“r” :テキストファイル読込みモード
    ファイルがなければエラー

“a” :追加書き込みモード
EOFより追加書き込みをする
ファイルがなければ新規作成

“rb” :”r”のバイナリ版
“wb” :”w”のバイナリ版
“ab” :”a”のバイナリ版
“r+” :更新用。”w”と同じ?
“w+” :”w”の更新モード
“a+” :”a”の更新モード
“r+b” or “rb+” :”rb”の更新モード
“w+b” or “wb+” :”wb”の更新モード
“a+b” or “ab+” :”ab”の更新モード

があります。
プラスが付く場合とそうでない場合をあまり意識していなかったので、実際のところ何が違うのかリファレンスで調べてみないとわからないところです。

以下に、ファイル操作の基本的なテンプレートを記述します。

#include<stdio.h>

main()
{
    FILE *fp;
    fp = fopen("readme.txt","w"); /* "w" のところがモード */

    /* ここにファイルの読み出し・書き込み処理を記述 */

    fclose(fp); /* ファイルのクローズ */
}

◇ファイル読み書き

1.ファイル読み込み

 ファイルを開いてもそれだけではデータを入力できません。
別に読み込みの作業が必要になります。順番として、

 ・ファイルのオープン
 ・データの入力(入力データがなくなるまで繰り返し)
 ・ファイルのクローズ

となります。
ファイルの読み込みの場合、ファイルが存在しない時のエラー出力も考慮しなくてはならないので、エラー処理も記述します。

#include<stdio.h>

main()
{
    FILE *fp;
    int  i;
    char str[128]="";
    char *fname = "readme.txt";
    fp = fopen(fname,"r");
    if(fp == NULL){
        printf("ファイル %s が存在しません。",fname);
    }
    else{
        for(i=0;i<128;i++){
            if((str[i] = getc(fp)) == EOF)break;
        }
    }
    fclose(fp); /* ファイルのクローズ */

    printf("%s\nが入力されました",str);
    return;
}

上のプログラムは、ファイルの先頭から1バイトずつ128バイトまで入力し表示するコードです。(日本語の途中で切れた時は文字化けするかもしれません。)

2.追加書き込み

今度は、さっき取得した文字列を追加書き込みします。

#include<stdio.h>

main()
{
    FILE *fp;
    int  i,j;
    char str[128]="";
    char *fname = "readme.txt";
    fp = fopen(fname,"r");
    if(fp == NULL){
        printf("ファイル %s が存在しません。",fname);
                return 0;
    }
    else{
        for(i=0;i<128;i++){
            if((str[i] = getc(fp)) == EOF)break;
        }
    }
    fclose(fp); /* ファイルのクローズ */

    printf("%s\nが入力されました",str);


/* 新しく追加した部分 */
    fp = fopen("backup.txt","a");
    i=0;
    for(j=0;j<=i;j++){
                putc(str[j],fp);
        }
    fclose(fp);

    return 0;
}

◇ファイル読み書き用関数

 ファイルデータの入出力に fprintf や fscanf,getc,putc など用いてきました。今回はこれらの関数について解説したいと思います。
 尚、fprintf,fscanfについては前に解説していますので省略させていただきます。

1.1文字読み込み

関数名   :getc
必要なヘッダ:stdio.h
関数のタイプ:int getc(FILE *stream);
引数    :stream FILE型変数へのポインタ
戻り値   :成功(読み取ったした文字)・失敗(EOF)

関数名   :fgetc
必要なヘッダ:stdio.h
関数のタイプ:int fgetc(FILE *stream);
引数    :stream FILE型変数へのポインタ
戻り値   :成功(読み取ったした文字)・失敗(EOF)

 上記のgetc,fgetcは同じ働きをします。

2.1文字書き込み

関数名   :putc
必要なヘッダ:stdio.h
関数のタイプ:int putc(int c, FILE *stream);
引数    :c 書き込む文字
       stream FILE型変数へのポインタ
戻り値   :成功(正の値)・失敗(EOF)

関数名   :fputc
必要なヘッダ:stdio.h
関数のタイプ:int fputc(int c, FILE *stream);
引数    :c 書き込む文字
       stream FILE型変数へのポインタ
戻り値   :成功(正の値)・失敗(EOF)

 こちらも同じくputc.fputcは同じ働きをします。

3.1行読み込み

関数名   :fgets
必要なヘッダ:stdio.h
関数のタイプ:char *fgets (char *s, int n, FILE *stream);
引数    :s 格納する文字列へのポインタ
       n 読み込む最大の文字数(\0まで含む)
       stream FILE型変数へのポインタ
戻り値   :成功 s へのポインタ
       失敗 NULLポインタ

サンプルプログラム

#include<stdio.h>

main()
{
        FILE *fp;
        char str[20],*pline;
        int  i;
        
        if ((fp = fopen("readme.txt","r")) == NULL)
                printf("ファイルがありません\n");
        else{
                if((pline = fgets(str,20,fp)) != NULL)
                        printf("%s\n",str);
                fclose(fp);
        }
        return 0;
}

4.1行書き込み

関数名   :fputs
必要なヘッダ:stdio.h
関数のタイプ:char *fputs (const char *s, FILE *stream);
引数    :s 書き込む文字列へのポインタ
       stream FILE型変数へのポインタ
戻り値   :成功(正の値)・失敗(EOF)

サンプルプログラム

#include<stdio.h>

main()
{
        FILE *fp;
        char str[20]="1行入力します",*pline;

        fp = fopen("reedme2.txt","w");
        fputs(str,fp);
        putc('\n',fp);
        fclose(fp);
        return 0;
}